﻿using Future.Common.Exception;
using Future.Common.Utils;
using Future.IService;
using Future.Model;
using Microsoft.AspNetCore.Authorization;
using System.Globalization;

namespace Future.Web.Controllers
{
    /// <summary>
    /// 文件处理控制器
    /// </summary>
    public class FileInfoController : AuthorizeController
    {
        private readonly IFileInfoBLL _fileInfoBLL;
        private readonly IFileService _fileService;
        private readonly ILogger<FileInfoController> _logger;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="fileInfoBLL"></param>
        /// <param name="fileService"></param>
        /// <param name="logger"></param>
        public FileInfoController(IFileInfoBLL fileInfoBLL
            , IFileService fileService
            , ILogger<FileInfoController> logger)
        {
            _fileInfoBLL = fileInfoBLL;
            _fileService = fileService;
            _logger = logger;
        }

        /// <summary>
        /// 获取头像，因为这里是img标签的src属性的get请求，这里没有token只有cookie所以这个不要求登录了
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Route("{id}")]
        [HttpGet]
        [AllowAnonymous]
        public FileResult GetAvatar(Guid id)
        {
            FileInfoModel fileInfo = _fileInfoBLL.GetFileInfoById(id);
            if (fileInfo is null || fileInfo.FilePath != FileTypeEnum.Image.ToString())
            {
                throw new BusinessException("文件信息不存在");
            }
            try
            {
                string path = Path.Combine(fileInfo.FilePath, fileInfo.Id.ToString() + fileInfo.FileType);
                FileStream stream = _fileService.GetFile(path);
                string MimeType = MimeUtil.GetMimeMapping(fileInfo.FileName);
                return File(stream, MimeType, fileInfo.FileName);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, message: ex.Message);
                throw new BusinessException("未找到文件");
            }
        }

        /// <summary>
        /// 多文件上传,type可空
        /// </summary>
        /// <param name="fileType">文件类型，可空</param>
        /// <param name="files">多文件表单</param>
        /// <param name="remark">描述</param>
        /// <returns></returns>
        [Route("{fileType?}")]
        [HttpPost]
        public List<Guid> Upload([FromRoute] string? fileType, [FromForm] IFormFileCollection files, [FromQuery] string? remark)
        {
            if (fileType is null)
            {
                fileType = FileTypeEnum.File.ToString();
            }
            else
            {
                fileType = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(fileType!.ToLower());
                if (!Enum.IsDefined(typeof(FileTypeEnum), fileType))
                {
                    throw new BusinessException("上传失败！文件类型不支持！");
                }
            }

            if (files.Count == 0)
            {
                throw new BusinessException("未选择文件");
            }

            List<FileInfoModel> fileInfoModels = new();
            foreach (IFormFile file in files)
            {
                if (file.Length <= 0)
                {
                    throw new BusinessException("文件异常");
                }

                FileInfoModel fileInfoModel = new()
                {
                    Id = Guid.NewGuid(),
                    FileSize = ((float)file.Length) / 1024,
                    FileName = file.FileName,
                    FileType = Path.GetExtension(file.FileName),
                    FilePath = fileType,
                    Remark = remark ?? string.Empty
                };

                string filename = fileInfoModel.Id.ToString() + fileInfoModel.FileType;
                string relativePath = Path.Combine(fileType, filename);
                using (MemoryStream stream = new())
                {
                    //将文件拷入内存，这里复制了一遍文件，会占用双倍的内存，但是IFormFile在asp的程序集中，不想在service里面引入asp的程序集。这里根据实际情况作出调整吧。
                    file.CopyTo(stream);
                    _fileService.WriteFile(relativePath, stream);
                }

                fileInfoModels.Add(fileInfoModel);
            }
            _fileInfoBLL.SaveInfos(fileInfoModels);
            return fileInfoModels.Select(x => x.Id).ToList();
        }
    }
}
